package com.siyoumi.app.modules.book.service;

import com.alibaba.fastjson.JSON;
import com.siyoumi.app.entity.*;
import com.siyoumi.app.modules.book.entity.BookInfo;
import com.siyoumi.app.modules.book.vo.*;
import com.siyoumi.app.modules.fun.service.SvcFun;
import com.siyoumi.app.service.BookRecordService;
import com.siyoumi.app.service.BookService;
import com.siyoumi.app.service.SysStockService;
import com.siyoumi.component.XApp;
import com.siyoumi.component.XBean;
import com.siyoumi.component.XSpringContext;
import com.siyoumi.component.http.InputData;
import com.siyoumi.component.http.XHttpContext;
import com.siyoumi.exception.EnumSys;
import com.siyoumi.mybatispuls.JoinWrapperPlus;
import com.siyoumi.service.IWebService;
import com.siyoumi.util.XDate;
import com.siyoumi.util.XReturn;
import com.siyoumi.util.XStr;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;

//预约
@Slf4j
@Service
public class SvcBook
        implements IWebService {
    static public SvcBook getBean() {
        return XSpringContext.getBean(SvcBook.class);
    }

    static public BookService getApp() {
        return BookService.getBean();
    }

    public String getUrl(String id) {
        String word = "book$action=info,book_id=" + id;
        return null;
    }


    /**
     * 总库存
     *
     * @param bookId
     */
    public BigDecimal getStockTotal(String bookId) {
        JoinWrapperPlus<BookSkuDay> query = SvcBookSkuDate.getBean().listQuery();
        query.eq("bday_book_id", bookId);
        return SvcBookSkuDate.getApp().sum(query, "stock_count_left + stock_count_use");
    }

    //地点 详情
    public BookInfo getInfo(String info) {
        if (XStr.isNullOrEmpty(info)) {
            return new BookInfo();
        }

        return JSON.parseObject(info, BookInfo.class);
    }

    public JoinWrapperPlus<Book> listQuery() {
        return listQuery(InputData.getIns());
    }

    /**
     * 能否预约
     *
     * @param bookId
     */
    public XReturn bookCan(String bookId, String openid) {
        Book entityBook = getApp().first(bookId);
        if (entityBook.getBook_del() != 0) {
            return XReturn.getR(20048, "预约不存在");
        }
        if (LocalDateTime.now().isBefore(entityBook.getBook_date_begin())) {
            return XReturn.getR(20058, "预约未开始");
        }
        if (LocalDateTime.now().isAfter(entityBook.getBook_date_end())) {
            return XReturn.getR(20068, "预约已结束");
        }

        if (entityBook.getBook_sign_fun_enable() == 1) {
            Long leftFun = SvcFun.getBean().getFun(openid);
            if (entityBook.getBook_sign_fun() > leftFun) {
                return XReturn.getR(20070, "用户积分不足");
            }
        }

        if (entityBook.getBook_sign_total() > 0) {
            Long recordCount = getRecordCount(bookId, openid, null, null);
            if (recordCount >= entityBook.getBook_sign_total()) {
                return XReturn.getR(20088, "用户总预约已到上限");
            }
        }

        return XReturn.getR(0);
    }

    public BookRecord getEntityRecord(String bookId, String key) {
        JoinWrapperPlus<BookRecord> query = listRecordQuery(bookId, null, null, null);
        query.eq("brecord_key", key);

        return BookRecordService.getBean().first(query);
    }

    public Long getRecordCount(String bookId, String openid, LocalDateTime bookDateBegin, LocalDateTime bookDateEnd) {
        JoinWrapperPlus<BookRecord> query = listRecordQuery(bookId, openid, null, null);
        query.join(BookSkuDay.table(), BookSkuDay.tableKey(), "brecord_bday_id");
        query.isNull("brecord_pid"); //过滤同行人记录
        if (bookDateBegin != null && bookDateEnd != null) {
            query.between("biday_date", bookDateBegin, bookDateEnd);
        }
        return BookRecordService.getBean().count(query);
    }

    //同行人
    public JoinWrapperPlus<BookRecord> listRecordAppendQuery(String recordId) {
        JoinWrapperPlus<BookRecord> query = BookRecordService.getBean().join();
        query.eq("brecord_x_id", XHttpContext.getX())
                .eq("brecord_pid", recordId);

        return query;
    }

    public JoinWrapperPlus<BookRecord> listRecordQuery(String bookId, String openid, LocalDateTime dateBegin, LocalDateTime dateEnd) {
        InputData inputData = InputData.getIns();
        inputData.put("openid", openid);
        if (dateBegin != null) {
            inputData.put("create_begin", XDate.toDateTimeString(dateBegin));
        }
        if (dateEnd != null) {
            inputData.put("create_end", XDate.toDateTimeString(dateEnd));
        }
        return listRecordQuery(bookId, inputData);
    }

    public JoinWrapperPlus<BookRecord> listRecordQuery(String bookId, InputData inputData) {
        String id = inputData.input("id");
        String openid = inputData.input("openid");
        String createBegin = inputData.input("create_begin");
        String createEnd = inputData.input("create_end");
        String status = inputData.input("status");
        String use = inputData.input("use");


        JoinWrapperPlus<BookRecord> query = BookRecordService.getBean().join();
        query.eq("brecord_x_id", XHttpContext.getX());
        if (XStr.hasAnyText(id)) { //ID
            query.eq("brecord_id", id);
        }
        if (XStr.hasAnyText(bookId)) { //预约ID
            query.eq("brecord_book_id", bookId);
        }
        if (XStr.hasAnyText(openid)) { //用户
            query.eq("brecord_wxuser_id", openid);
        }
        if (XStr.hasAnyText(status)) { //审核状态
            query.eq("brecord_state", status)
                    .isNull("brecord_pid");
        }
        if (XStr.hasAnyText(use)) { //核销状态
            query.eq("brecord_use", use)
                    .isNull("brecord_pid");
        }
        if (XStr.hasAnyText(createBegin) && XStr.hasAnyText(createEnd)) { //创建时间
            LocalDateTime b = XDate.parse(createBegin);
            LocalDateTime e = XDate.parse(createEnd);
            query.between("brecord_create_date", b, e);
        }


        return query;
    }

    /**
     * select
     *
     * @return query
     */
    public JoinWrapperPlus<Book> listQuery(InputData inputData) {
        String name = inputData.input("name");
        String groupId = inputData.input("group_id");

        JoinWrapperPlus<Book> query = getApp().join();
        query.eq("book_x_id", XHttpContext.getX())
                .eq("book_del", 0);
        query.orderByAsc("book_order")
                .orderByDesc("book_create_date");

        if (XStr.hasAnyText(name)) { //名称
            query.like("book_name", name);
        }

        return query;
    }

    /**
     * 编辑
     *
     * @param inputData
     * @param vo
     */
    @Transactional(propagation = Propagation.MANDATORY)
    @SneakyThrows
    public XReturn edit(InputData inputData, VaBook vo) {
        XReturn r = getApp().saveEntity(inputData, vo, true, null);
        return r;
    }

    /**
     * 删除
     */
    public XReturn delete(List<String> ids) {
        JoinWrapperPlus<Book> query = listQuery();
        query.in(Book.tableKey(), ids)
                .eq("book_del", 0);

        List<Book> list = getApp().list(query);
        XApp.getTransaction().execute(status -> {
            for (Book entity : list) {
                getApp().delete(entity.getKey());
            }

            return null;
        });

        return EnumSys.OK.getR();
    }

    public XReturn bookSubmitCan(VaBookSumbit vo) {
        BookSkuDay entitySkuDay = SvcBookSkuDate.getApp().first(vo.getDay_id());
        if (entitySkuDay == null) {
            return XReturn.getR(20177, "日期ID异常");
        }
        if (entitySkuDay.getBday_del() == 1) {
            return XReturn.getR(20179, "日期已删除");
        }

        XReturn r = bookCan(entitySkuDay.getBday_book_id(), getOpenid());
        if (r.err()) {
            return r;
        }

        SysStock entityLeft = SysStockService.getBean().getEntityBySrc(entitySkuDay.getKey(), false);
        if (entityLeft.getStock_count_left() <= 0) {
            return XReturn.getR(20187, "库存不足");
        }

        Book entityBook = getApp().first(entitySkuDay.getBday_book_id());
        if (entityBook.getBook_sign_day_total() > 0) {
            //选择日期预约上限
            LocalDateTime b = entitySkuDay.getBday_date();
            LocalDateTime e = entitySkuDay.getBday_date().plusDays(1).minusSeconds(1);

            Long recordCount = getRecordCount(entitySkuDay.getBday_book_id(), getOpenid()
                    , b
                    , e);
            if (recordCount >= entityBook.getBook_sign_day_total()) {
                return XReturn.getR(20098, XStr.format("用户{0}预约已到上限", XDate.toDateString(b)));
            }
        }

        BookSku entitySku = SvcBookSku.getApp().first(entitySkuDay.getBday_sku_id());
        //截止时间
        Long m = entitySku.getBsku_before_time();
        if (entitySkuDay.getBday_before_enable() == 1) {
            //日期特殊设置
            m = entitySkuDay.getBday_before_time();
        }
        LocalDateTime dateTimeEnd = SvcBookSku.getBean().getDateTimeEnd(entitySku
                , XDate.toDateString(entitySkuDay.getBday_date())
                , m);
        if (LocalDateTime.now().isAfter(dateTimeEnd)) {
            return XReturn.getR(20197, "时间段已截止预约");
        }

        String key = entitySkuDay.getKey() + "|" + getOpenid();
        BookRecord entityRecord = getEntityRecord(entityBook.getBook_id(), key);
        if (entityRecord != null) {
            return XReturn.getR(20207, "同个时间段只能报名1次");
        }

        return XReturn.getR(0);
    }

    @SneakyThrows
    public XReturn bookSubmit(VaBookSumbit vo) {
        XReturn r = bookSubmitCan(vo);
        if (r.err()) {
            return r;
        }
        BookSkuDay entitySkuDay = SvcBookSkuDate.getApp().first(vo.getDay_id());
        if (vo.getAppends() != null && vo.getAppends().size() > entitySkuDay.getBday_append_max()) {
            return XReturn.getR(20180, "同行人不能大于" + entitySkuDay.getBday_append_max());
        }

        Book entityBook = getApp().first(entitySkuDay.getBday_book_id());
        String key = entitySkuDay.getKey() + "|" + getOpenid();

        BookRecord entity = new BookRecord();
        XBean.copyProperties(vo, entity);
        entity.setBrecord_x_id(XHttpContext.getX());
        entity.setBrecord_book_id(entitySkuDay.getBday_book_id());
        entity.setBrecord_bday_id(entitySkuDay.getKey());
        entity.setBrecord_wxuser_id(getOpenid());
        entity.setBrecord_key(key);
        entity.setBrecord_id(XApp.getStrID());

        return XApp.getTransaction().execute(transactionStatus -> {
            BookRecordService.getBean().save(entity);

            log.info("报名扣库存");
            SysStockService.getBean().subStock(entity.getBrecord_bday_id(), 1L);

            if (entityBook.getBook_sign_fun_enable() == 1) {
                //报名消耗积分
                String funKey = "sign_fun|" + entity.getBrecord_id();
                SvcFun.getBean().add(funKey
                        , entity.getBrecord_wxuser_id()
                        , entityBook.getKey()
                        , "book"
                        , entityBook.getBook_sign_fun()
                        , "报名消耗积分"
                        , entity.getBrecord_id()
                        , "");
            }

            if (entityBook.getBook_audit_enable() != 1) {
                //无需审核
                VaBookAudit bookAudit = new VaBookAudit();
                bookAudit.setStatus(1);
                bookAudit.setRecord_id(entity.getBrecord_id());
                bookAudit.setSendMsg(false);
                bookAudit(bookAudit);
            }

            //同行人添加
            if (vo.getAppends() != null) {
                for (VaBookSumbitAppend item : vo.getAppends()) {
                    BookRecord entityAppend = new BookRecord();
                    try {
                        BeanUtils.copyProperties(entityAppend, entity);
                        BeanUtils.copyProperties(entityAppend, item);
                    } catch (Exception e) {
                    }
                    entityAppend.setBrecord_key(null);
                    entityAppend.setBrecord_pid(entity.getBrecord_id());
                    entityAppend.setBrecord_id(XApp.getStrID());
                    BookRecordService.getBean().save(entityAppend);
                }
            }

            XReturn rr = XReturn.getR(0);
            rr.setData("entity", entity);
            return rr;
        });
    }

    /**
     * 预约审核
     */
    public XReturn bookAudit(VaBookAudit vo) {
        BookRecord entityRecord = BookRecordService.getBean().first(vo.getRecord_id());
        if (entityRecord == null) {
            return XReturn.getR(20349, "预约ID异常");
        }
        if (entityRecord.getBrecord_state() != 0) {
            return XReturn.getR(20359, "预约已审核");
        }
        if (XStr.hasAnyText(entityRecord.getBrecord_pid())) {
            return XReturn.getR(0, "同行人订单，无需审核");
        }
        if (entityRecord.getBrecord_cancel() != 0) {
            return XReturn.getR(0, "订单已取消");
        }

        Book entityBook = getApp().first(entityRecord.getBrecord_book_id());

        return XApp.getTransaction().execute(transactionStatus -> {
            BookRecord entityRecordUpdate = new BookRecord();
            entityRecordUpdate.setBrecord_id(entityRecord.getBrecord_id());
            entityRecordUpdate.setBrecord_state(vo.getStatus());
            if (vo.getStatus() == -1) {
                log.info("不通过，key设置为随机数");
                entityRecordUpdate.setBrecord_key(XApp.getStrID());
            }
            entityRecordUpdate.setBrecord_state_date(LocalDateTime.now());
            BookRecordService.getBean().save(entityRecordUpdate);

            if (vo.getStatus() == 1) {
                log.info("审核通过");
                if (entityBook.getBook_sign_give_enable() == 1) {
                    log.info("报名奖励积分");
                    String funKey = "sign_give|" + entityRecord.getBrecord_id();
                    SvcFun.getBean().add(funKey
                            , entityRecord.getBrecord_wxuser_id()
                            , entityRecord.getBrecord_book_id()
                            , "book"
                            , entityBook.getBook_sign_give_fun()
                            , "报名奖励积分"
                            , entityRecord.getBrecord_id()
                            , ""
                    );
                }
            } else {
                log.info("审核不通过");
                if (entityBook.getBook_sign_fun_enable() == 1) {
                    log.info("报名返还积分");
                    String funKey = "sign_fun_back|" + entityRecord.getBrecord_id();
                    SvcFun.getBean().add(funKey
                            , entityRecord.getBrecord_wxuser_id()
                            , entityRecord.getBrecord_id()
                            , "book"
                            , entityBook.getBook_sign_fun()
                            , "报名审核不通用返还积分"
                            , entityRecord.getBrecord_id()
                            , ""
                    );
                }

                log.info("报名返还库存");
                SysStockService.getBean().subStock(entityRecord.getBrecord_bday_id(), -1L);
            }

            XReturn r = XReturn.getR(0);
            return r;
        });
    }

    /**
     * 有效订单
     *
     * @param entityRecord
     */
    public XReturn validRecord(BookRecord entityRecord) {
        if (entityRecord == null) {
            return XReturn.getR(20349, "预约ID异常");
        }
        if (entityRecord.getBrecord_use() != 0) {
            return XReturn.getR(20369, "预约已核销");
        }
        if (entityRecord.getBrecord_cancel() != 0) {
            return XReturn.getR(20381, "预约已取消");
        }
        if (XStr.hasAnyText(entityRecord.getBrecord_pid())) {
            return XReturn.getR(20389, "同行人订单，不能核销");
        }

        return XReturn.getR(0);
    }

    /**
     * 预约核销
     *
     * @param vo
     */
    public XReturn bookUse(VaBookUse vo) {
        BookRecord entityRecord = BookRecordService.getBean().first(vo.getRecord_id());
        XReturn r = validRecord(entityRecord);
        if (r.err()) {
            return r;
        }

        if (entityRecord.getBrecord_state() != 1) {
            return XReturn.getR(20359, "预约未通过");
        }

        BookRecord entityRecordUpdate = new BookRecord();
        entityRecordUpdate.setBrecord_id(entityRecord.getBrecord_id());
        entityRecordUpdate.setBrecord_use(1);
        entityRecordUpdate.setBrecord_use_date(LocalDateTime.now());
        BookRecordService.getBean().updateById(entityRecordUpdate);

        return XReturn.getR(0);
    }

    /**
     * 预约取消
     *
     * @param vo
     */
    public XReturn bookCancel(VaBookCancel vo) {
        BookRecord entityRecord = BookRecordService.getBean().first(vo.getRecord_id());
        XReturn r = validRecord(entityRecord);
        if (r.err()) {
            return r;
        }

        XApp.getTransaction().execute(transactionStatus -> {
            BookRecord entityRecordUpdate = new BookRecord();
            entityRecordUpdate.setBrecord_id(entityRecord.getBrecord_id());
            entityRecordUpdate.setBrecord_cancel(1);
            entityRecordUpdate.setBrecord_cancel_date(LocalDateTime.now());
            BookRecordService.getBean().updateById(entityRecordUpdate);

            Book entityBook = getApp().first(entityRecord.getBrecord_book_id());
            if (entityBook.getBook_sign_cancel() == 1) {
                log.info("取消预约并审核通过，退积分");
                if (entityBook.getBook_sign_fun_enable() == 1 && entityRecord.getBrecord_state() == 1) {
                    String funKey = "sign_fun_cancel|" + entityRecord.getBrecord_id();
                    SvcFun.getBean().add(funKey
                            , entityRecord.getBrecord_wxuser_id()
                            , entityRecord.getBrecord_book_id()
                            , "book"
                            , entityBook.getBook_sign_fun()
                            , "报名取消返还积分"
                            , entityRecord.getBrecord_id()
                            , "");
                }
            }

            return null;
        });


        return XReturn.getR(0);
    }
}
